﻿Imports System.Xml.Serialization
Namespace OpenArchive
    Namespace System
        Namespace DB
            <Serializable(), XmlRoot("IndexField(Of T)")> _
            Public Class IndexField(Of T)
                Implements Xml.Serialization.IXmlSerializable


                Private m_IsNumeric As Boolean
                Private m_IsString As Boolean
                Private m_IsDate As Boolean
                Private m_value As Object
                Private m_QueryTerm As String
                Private Sub New()
                    m_IsNumeric = CheckIsNumeric(GetType(T))
                    m_IsString = CheckIsString(GetType(T))
                    m_IsDate = IsDate(GetType(T))
                End Sub
                Private Sub New(ByVal value As String)
                    Me.New()
                    If m_IsString Then
                        m_value = value
                        m_QueryTerm = value
                    End If
                    If m_IsNumeric Then
                        m_value = Activator.CreateInstance(GetType(T))
                        m_value.TryParse(value, m_value)
                    End If
                    If m_IsDate Then
                        DateTime.TryParse(value, m_value)
                    End If
                    m_QueryTerm = value
                End Sub

                Public Overloads Shared Widening Operator CType(ByVal value As T) As IndexField(Of T)
                    Return New IndexField(Of T)(value.ToString)
                End Operator
                Public Shared Operator =(ByVal value1 As IndexField(Of T), ByVal value2 As IndexField(Of T)) As Boolean
                    Return value1.Value.ToString = value2.Value.ToString
                End Operator
                Public Shared Operator <>(ByVal value1 As IndexField(Of T), ByVal value2 As IndexField(Of T)) As Boolean
                    Return value1.Value.ToString <> value2.Value.ToString
                End Operator
                Public Overloads Shared Narrowing Operator CType(ByVal value As String) As IndexField(Of T)
                    Return New IndexField(Of T)(value)
                End Operator
                Public Overloads Shared Narrowing Operator CType(ByVal value As IndexField(Of T)) As T
                    Return value.Value
                End Operator
                Public ReadOnly Property Value() As T
                    Get
                        If m_value Is Nothing Then
                            Throw New InvalidOperationException("NoValue")
                        End If
                        Return m_value
                    End Get
                End Property
                Public ReadOnly Property Type() As Type
                    Get
                        Return GetType(T)
                    End Get
                End Property
                Public ReadOnly Property IsNumeric() As Boolean
                    Get
                        Return m_IsNumeric
                    End Get
                End Property
                Public ReadOnly Property IsString() As Boolean
                    Get
                        Return m_IsString
                    End Get
                End Property

                Private Function IsDate(ByVal type As Type) As Boolean
                    If Not type.IsEnum Then
                        If type.GetTypeCode(type) = TypeCode.DateTime Then Return True
                    End If
                End Function
                Private Function CheckIsNumeric(ByVal type As Type) As Boolean
                    If Not type.IsEnum Then
                        Select Case type.GetTypeCode(type)
                            Case TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double
                                Return True
                        End Select
                    End If
                    Return False
                End Function
                Private Function CheckIsString(ByVal type As Type) As Boolean
                    If Not type.IsEnum Then
                        Select Case type.GetTypeCode(type)
                            Case TypeCode.String
                                Return True
                        End Select
                    End If
                End Function

                Public ReadOnly Property QueryTerm() As String
                    Get
                        Return m_QueryTerm
                    End Get
                End Property

                Public Overrides Function Equals(ByVal other As Object) As Boolean
                    If m_value Is Nothing Then
                        Return (other Is Nothing)
                    End If
                    If (other Is Nothing) Then
                        Return False
                    End If
                    Return Me.m_value.Equals(other)
                End Function

                Public Overrides Function GetHashCode() As Integer
                    If m_value Is Nothing Then
                        Return 0
                    End If
                    Return Me.m_value.GetHashCode
                End Function

                Public Overrides Function ToString() As String
                    If m_value Is Nothing Then
                        Return ""
                    End If
                    Return Me.m_value.ToString
                End Function

                Public Function GetSchema() As Xml.Schema.XmlSchema Implements Xml.Serialization.IXmlSerializable.GetSchema
                    Return Nothing
                End Function

                Public Sub ReadXml(ByVal reader As Xml.XmlReader) Implements Xml.Serialization.IXmlSerializable.ReadXml
                    Dim _Serializer As XmlSerializer = New XmlSerializer(GetType(T))
                    Dim _wasEmpty As Boolean = reader.IsEmptyElement
                    reader.Read()
                    If _wasEmpty Then Return
                    reader.ReadStartElement("value")
                    Dim value As T = DirectCast(_Serializer.Deserialize(reader), T)
                    reader.ReadEndElement()
                    m_value = value
                End Sub

                Public Sub WriteXml(ByVal writer As Xml.XmlWriter) Implements Xml.Serialization.IXmlSerializable.WriteXml
                    Dim _Serializer As XmlSerializer = New XmlSerializer(GetType(T))
                    writer.WriteStartElement("value")
                    _Serializer.Serialize(writer, m_value)
                    writer.WriteEndElement()
                End Sub
            End Class

        End Namespace
    End Namespace
End Namespace